package com.yswy.backstage.utils;

import com.yswy.common.utils.DoudouBase64;

import java.io.*;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;

/**
 * RSA加密、签名区别
 * 加密和签名都是为了安全性考虑，但略有不同。常有人问加密和签名是用私钥还是公钥？其实都是对加密和签名的作用有所混淆。简单的说，加密是为了防止信息被泄露，而签名是为了防止信息被篡改。这里举2个例子说明。
 * 第一个场景：战场上，B要给A传递一条消息，内容为某一指令。
 * RSA的加密过程如下：
 * （1）A生成一对密钥（公钥和私钥），私钥不公开，A自己保留。公钥为公开的，任何人可以获取。
 * （2）A传递自己的公钥给B，B用A的公钥对消息进行加密。
 * （3）A接收到B加密的消息，利用A自己的私钥对消息进行解密。
 * 　　在这个过程中，只有2次传递过程，第一次是A传递公钥给B，第二次是B传递加密消息给A，即使都被敌方截获，也没有危险性，因为只有A的私钥才能对消息进行解密，防止了消息内容的泄露。
 * 第二个场景：A收到B发的消息后，需要进行回复“收到”。
 * RSA签名的过程如下：
 * （1）A生成一对密钥（公钥和私钥），私钥不公开，A自己保留。公钥为公开的，任何人可以获取。
 * （2）A用自己的私钥对消息加签，形成签名，并将加签的消息和消息本身一起传递给B。
 * （3）B收到消息后，在获取A的公钥进行验签，如果验签出来的内容与消息本身一致，证明消息是A回复的。
 * 　　在这个过程中，只有2次传递过程，第一次是A传递加签的消息和消息本身给B，第二次是B获取A的公钥，即使都被敌方截获，也没有危险性，因为只有A的私钥才能对消息进行签名，即使知道了消息内容，也无法伪造带签名的回复给B，防止了消息内容的篡改。
 * <p>
 * 加密、解密工具类
 *
 * @date 2019/2/22
 */
public class RSACryptUtil {
    //公钥 base64字符串
    private static final String PUPBLICKEY_BASE64_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVbSzlHqPW+Sb61TyDGKvj6Ev4YMj2SxmNzxvJF66Qkkg6s7PkuzNXyFuTOZw8vnwnW2UFV8SeiVHARpdJXDLLnw2L+abuFAEsytGFB9CGbU73KNdojHRBP4ON15B4mh/PXAaVgj0zvgU1P8F4Q9IC0p0b6X+/RnmMxDoiWvGSYwIDAQAB";
    //私钥 base64字符串
    private static final String PRIVATEKEY_BASE64_STR = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJVtLOUeo9b5JvrVPIMYq+PoS/hgyPZLGY3PG8kXrpCSSDqzs+S7M1fIW5M5nDy+fCdbZQVXxJ6JUcBGl0lcMsufDYv5pu4UASzK0YUH0IZtTvco12iMdEE/g43XkHiaH89cBpWCPTO+BTU/wXhD0gLSnRvpf79GeYzEOiJa8ZJjAgMBAAECgYEAjFhYXHJkzBqDZAA3r6HSgGLER+sPlVSAEdM+c6dMi/j44jm6ctDorkA+0o6/kcYPch/DSDthLs4m/ILQwVRZV7plFlJ8sZ4Xk/k8qWPd/LhwhOOkkM56YaSb5rTp6H++pbvfOdfi9ngW5WC+8RWY72LnhoQYV7AtMDUqLkwJ71ECQQDPjwrH+3GTqgz7pUSZLkUgG/RAE4vU3J81SpvjzQ85FES897xnczyCizAuh35U2x1gCHkB6umzW/hk5yS1MnntAkEAuEzrLrZ5TdIcyVbg2Vaidg9Y1Ry2TP5VZQoG1cZVauWjlMgJ+driBG5xiMDcLZb+wFUhsAfnrjpuymYdq6JzjwJBALouYopet1OwzzKP3gfV5HXX/XHY1q6bNEjWYx2lXIlj8ADd7GeTi+zBs/eY3K57Wk9BamJY+UdFMXw5hsjuvUUCQDxP97r+vi3Ib+E3zDdz0ZC/Lvv2/HWv2bRKFriIwlVMNz8uQ41/ou1+UytEqglFW7MHaRHZVGlA+BbGWjlb3WMCQC2KTzpW9G5gwvzzUAHp9/z9gsm37ldlzSjbOuhG2QX4Vxt0/jkOERgYcFTylQxXcl7xwscj5Y9aQpXENSeJSoE=";

//    //第二个公钥 base64字符串
//    private static final String SECOND_PUPBLICKEY_BASE64_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiQjrAAmGKIc9bmH8Ar9e8mANy" +
//            "L9qjlvzbePVoaSFvhypZ1YJeyzy6qTbeA2X6kmoNw3gX2NzLX4InflVtN4idAZDh" +
//            "N1F+RQCt3fuTixAZLEjP62XHJ7qE2cZ+3Bc2A9gPyNyJ6EtSCzzYK+9Q1g43F4Xi" +
//            "2Zk2ch9Zwp86/iEoZQIDAQAB";
//
//    //第二个私钥 base64字符串
//    private static final String SECOND_PRIVATEKEY_BASE64_STR = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKJCOsACYYohz1uY" +
//            "fwCv17yYA3Iv2qOW/Nt49WhpIW+HKlnVgl7LPLqpNt4DZfqSag3DeBfY3Mtfgid+" +
//            "VW03iJ0BkOE3UX5FAK3d+5OLEBksSM/rZccnuoTZxn7cFzYD2A/I3InoS1ILPNgr" +
//            "71DWDjcXheLZmTZyH1nCnzr+IShlAgMBAAECgYBeBvc4saiIfZNGRxbB9SSVu5mz" +
//            "oBuZVTPukyfTe6jOkotuR5YnDKuCl/Cds2ZzUEl49F8xopBAonYwILuscNQPC8XK" +
//            "cxDngMushQbW2JiHOy15KiF0rHP7vokbmDxx7Sv4v7H42jM+9EtCUcEZk7idngLq" +
//            "37jBCyxSs8cUUek/gQJBANBXDUCIT4IuqG12Riedt00I4OD84iw43vhUKfTIWERx" +
//            "Qv+4BUcje6rmYj6sVMpAOWP0njV1aUXnAP/2AmjDbHECQQDHYIgm3X7UYPvLqO9K" +
//            "nj0fnn2YusoBsKSjCPkSctVuong0gR5l8bp5BVoUqJJ0HBEY2avWcRliU1naChW6" +
//            "JYU1AkEAvI99RAHbDDUUZXXdiu94vjUh6x+VyHZ0f4cVLiHBmbh07iLsS/V2cTfw" +
//            "hU7NsvurtabpJfMtI4Iu6nsKtSziUQJAIcr2yL+aE50skGRdyqPvcECIwS5Htumd" +
//            "vhRzQvE7w7i97whDgrvqA0Eo939q80seiru6KGqbBtNh01cKP7bEUQJBAIfk5Bhn" +
//            "XM2/ll9+yU1IgPzuiwl81CSbXJLM5XHk9FencXR4lVZoqVXfv8NWBN7s5YjzgsCg" +
//            "HYkdOjnGjzi6XXM=";

    private static String SECOND_PRIVATEKEY_BASE64_STR = "";
    private static String PRIVATEKEY_BASE64_STR_4 = "";

    // 指定加密算法为RSA
    private static final String ALGORITHM = "RSA/ECB/PKCS1Padding";
    // RSA最大加密明文大小
    private static final int MAX_ENCRYPT_BLOCK = 117;
    // RSA最大解密密文大小
    private static final int MAX_DECRYPT_BLOCK = 128;
    //这个base64用来解码key的
    private static DoudouBase64 keyBase64 = new DoudouBase64(DoudouBase64.normalKey);
    //这个base64用来加解码秘文
    private static DoudouBase64 theOnleyBase64 = new DoudouBase64("2hTDbk_Q7q0WoKry=pCFmIaJ1Lj8MxPYAVcXdEflzu94ntgBwUH5iRvGS3Z6O-seN");

    //当前使用的密钥base64字符串，客户端这个值应该是公钥，服务端应该是私钥，客户端不能保留私钥的任何信息
    private String KEY_BASE64_STR;
    private Key key = null;

    private static RSACryptUtil client = null;
    private static RSACryptUtil server = null;

    public static void setSECOND_PRIVATEKEY_BASE64_STR(String sPriStr) {
        SECOND_PRIVATEKEY_BASE64_STR = sPriStr;
    }



    /**
     * 服务端专用工具
     *
     * @return
     */
    public static RSACryptUtil getServerUtil() {
        if (server == null) {
            server = new RSACryptUtil();
        }
        return server;
    }

    public static String getPublickKey(boolean isOld) {
        if (isOld) {
            return PUPBLICKEY_BASE64_STR;
        }
        return null;
    }
    public static String getPrivateKey(boolean isOld) throws Exception {
        if (isOld) {
            return PRIVATEKEY_BASE64_STR;
        }
        String decrypt = RSAUtils.decrypt(SECOND_PRIVATEKEY_BASE64_STR, RSAUtils.getPrivateKey(RSAUtils.privateKey));
        return decrypt;
    }

    /**
     * 客户端专用工具
     *
     * @return
     */
    public static RSACryptUtil getClientUtil() {
        if (client == null) {
            client = new RSACryptUtil();
        }
        return client;
    }


    //分段加密
    public String encrypt(String source, String key, boolean isPublic) throws Exception {
        // 得到Cipher对象来实现对源数据的RSA加密
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, getKey(key,isPublic));
        byte[] b = source.getBytes("utf-8");
        int inputLen = b.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(b, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(b, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        String resource = theOnleyBase64.encode2String(encryptedData);
        return resource;
    }

    //分段解密
    public String decrypt(String encryptedData, String key, boolean isPublic) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, getKey(key,isPublic));
        //encryptedData = decomposeTarget(encryptedData);
        byte[] target = theOnleyBase64.decode(encryptedData.getBytes("utf-8"));
        int inputLen = target.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(target, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(target, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return new String(decryptedData, "UTF-8");
    }


    /**
     * 获取密钥
     *
     * @return
     * @throws Exception
     * @throws IOException
     */
    private Key getKey(String keyBas64eStr,boolean isPublic) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
        if (key == null) {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            if (isPublic) {
                byte[] keyData = keyBase64.decode(keyBas64eStr.getBytes("utf8"));
                X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyData);
                return keyFactory.generatePublic(keySpec);
            } else {
                byte[] keyData = keyBase64.decode(keyBas64eStr.getBytes("utf8"));
                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyData);
                return keyFactory.generatePrivate(keySpec);
            }
        } else {
            return key;
        }
    }

    /**
     * 拼接字符串
     *
     * @param resource
     */
    private String composeResource(String resource) {
        StringBuilder stringBuilder = new StringBuilder();
        String time = String.valueOf(System.currentTimeMillis());
        stringBuilder.append(resource).append("timestamp").append(time);
        return stringBuilder.toString();
    }

    /**
     * 截取字符串
     *
     * @param target
     */
    private String decomposeTarget(String target) {
        int index = target.lastIndexOf("timestamp");
        String time = target.substring(index);
        String tar = target.substring(0, index);
        return tar;
    }


    public static void main(String[] a) throws Exception {
        RSACryptUtil client = getClientUtil();
        RSACryptUtil server = getServerUtil();



//        String enData = "/v2/getHuaweiObsSignedUrl?uploadFilePath=backupFiles/c23b9c8e13574ef189c598328861af15/1b32f5b3f51840fa8e9fcb47ab0c1c64.zip&signedUrlType=1&deviceinfoId=300334877&currentImei=123456789123456&currentMac=02:00:00:00:00:00&bootId=41198f19-2366-4d44-9e5f-512075db5262&timestamp=1608377085390&currentDeviceId=185fe7eecd4349efa02e83c3a8df514e&u=&cr=0&ur=2&hook=0&token=false&os_sn=dc681391f979d5e57115ce2f30c54589&osv=700204&app_sn=8466135767c8ffddb5f235ac6e064b2b&kl_sn=190fb80fc2a54130b0d5012874c7fbdc";
//        String encrypt = client.encrypt(enData,SECOND_PUPBLICKEY_BASE64_STR,true);
//        System.out.println("encrypt:\n"+encrypt);
//
//        String data = "lYpG3VkKvyiEp-Oz8CyjOkRjcaGCxpfQlI-aoLQRCLKh-82StXYHqlj3ppc0x_wgl_Orn233-zDRUE-sE--PQjU1LJDpXfZnLdKUa77u1r24veFi9ygVanExz9YKzi0zKkjYdUWBUAhV-3nwt=CcQEqDpIp517oHf_IP6TSvtVcK3bYZ6SCbJ0lL0f068=rfO_h5Qq=WhZH4BXIwMYKmDkHppuYP1wgyViJdjYYlW6JEwvxdQWBasSdak_4MhMzvhKnbXWEFcz9b=yk1ehK8kkkWDwf2eW95MK=5-lz84IzIT9f1bPpVvRK2MTUkz8YVbmYuaA9OYCVJcS6adaSrvLSnUm_2A12SCeLFs=uLoHtzbgO1PipyGx0IXyWeMDWD1vcu8sp==6e-9yLEB0ARyrBJsABVSlBMy0CCvny=ObghZZ=V5=b0nKCj6P916j2X0azgufRoJ_Rwj25FVZDWlxjZQBnz9KXTyKYmMjuS1UiwWEXL-O9mI6oDagY_x=_Uo6dZ3x0W3r15Ulj78-nVwcYd25y28pHrdzBxCJcq-ePmEeSrVRbIfzRd6PIxZabt=7qgd0I3OBxP3gjv-GXmwkTaFjGVnsp_x85saF7o03JTdLU=SI1QVjVqns_7KV=obbrv2siibHAuuuGfuLtJabfliekBL71HbbPa=z9-lP=6cqjrFnAi5UvTClmksk_2mUlO_Wt3vZ2nv2QDpacJPvQmcGoBWxdZT_8zxqk1mtJg0Fg3IJD=7AQIziEl2aLvOnjEA50xduhPHugnBx3jkMcLpM1JX8PTABFMa5ZEd1A=yroB5Js7OKkf2MT8j_ddd3zPx-JLPwTPMPazTY=ynwNN";
//
//        String decrypt = client.decrypt(data,SECOND_PUPBLICKEY_BASE64_STR,true);
//        System.out.println("decrypt:\n"+decrypt);


//        byte[] bytes = decrypt.getBytes();
//        byte[] encrpytBytes = new byte[bytes.length];
//        for (int i = 0; i < bytes.length; i++) {
//            byte b =  bytes[i];
//            b-=2;
//            encrpytBytes[i]=b;
//        }
//        decrypt = new String(encrpytBytes);
//        System.out.println("2decrypt:"+decrypt);

//        String decrypt = client.decrypt(data, SECOND_PRIVATEKEY_BASE64_STR, false);
//        System.out.println(decrypt);

        String uriAndData = "hrQPBLEg6fqQACkp_0PLDsV_bLq-g7YYBpWh8ua6btv5Tq0W_ZnCpwgFnTUMEkYbvVVu6zTzB_ThqicYKzT8x=tAkFbbHiph8j7JZwjT8XL84tS6k6BBOliZ8nrkpR0BEgv6UInWCdAxxJbfs6mfy_YhoK5vLrZxFqDvInYiKlLd_G=vXhMusrSh9F2K1PglpbbtUaZMJhvnIePJFLKXkzKpBFLzgb6GGnJlnLl=vr6bD7C2RvldEpqegByFQzoc0nkUYfmnvL6GyLae5zpueIR91zhq1gD8Iv7tAePl1Gq0blUC0DUMjO1t2Q_ETzvqtDC_pMkaWajbOWuJxMZg9mPXugi7inuzYU3upqHx6w6iMx3-4Tv8r8CzHzhM7oSPLbomkIys1huOMD3Gctz5fz2R1d-RLjXM6bxO1z52KCpEZbcelw94fuG3FrrBa3shEAVkpFisVrQp1xqay_9BJUSOOKwaDDHWlTKSqzTJKtJ7Djinoho5o5GSB9xUCaAa";
        String decodeData = RSACryptUtil.getServerUtil().decrypt(uriAndData, RSACryptUtil.getPrivateKey(true), false);
        System.out.println(decodeData);
//
//        String s ="{\"pageIndex\":1,\"pageSize\":10,\"isSale\":false,\"isTask\":1}";
//        String decodeData = RSACryptUtil.getClientUtil().encrypt(s, RSACryptUtil.getPublickKey(true) ,false);
//        decodeData = RSACryptUtil.getServerUtil().decrypt(decodeData, RSACryptUtil.getPrivateKey(true), false);
                //        byte[] bytes = uriAndData.getBytes();
//        byte[] encrpytBytes = new byte[bytes.length];
//        for (int i = 0; i < bytes.length; i++) {
//            byte b =  bytes[i];
//            b-=2;
//            encrpytBytes[i]=b;
//        }
       // System.out.println(decodeData);

    }


    public static String getPrivatekeyBase64Str4() throws Exception {
        String decrypt = RSAUtils.decrypt(PRIVATEKEY_BASE64_STR_4, RSAUtils.getPrivateKey(RSAUtils.privateKey));
        return decrypt;
    }

    public static void setPrivatekeyBase64Str4(String privatekeyBase64Str4) {
        PRIVATEKEY_BASE64_STR_4 = privatekeyBase64Str4;
    }


}
